﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Text;
using System.Linq;
using ExcelDataReader;
using System.Data;
using System.Collections.Concurrent;
using System.Threading.Tasks;
using System.Diagnostics;
using ExcelImport.Validators;

namespace ExcelImport
{
    public class ExcelImporter
    {
        private static ConcurrentDictionary<Type, ImportTable> _typeCaches = new ConcurrentDictionary<Type, ImportTable>();

        private IDatabase _db;

        private ImporterOptions _importerOptions;

        public ExcelImporter(IDatabase db)
        {
            this._db = db;
        }

        #region Methods
        public bool Import<T>(Stream stream, out IEnumerable<ValidationResult> validationResults) where T : class, new()
        {
            ImportTable importTable = CreateImportTable<T>();

            DataTable dt = StreamToDataTable(stream, importTable);

            DataProcessPipeline dataProcessPipeline = CreateDataProcessPipeline(importTable);

            dataProcessPipeline.Run(dt);

            validationResults = dataProcessPipeline.ValidationContext.GetValidationResults();

            if (dataProcessPipeline.ValidationContext.HasError)
            {
                return false;
            }

            this._db.BlukCopy<T>(dt, importTable);
            return true;
        }

        #endregion

        #region Helper

        /// <summary>
        /// 获取数据验证管道实例
        /// </summary>
        /// <param name="importTable"></param>
        /// <returns></returns>
        private DataProcessPipeline CreateDataProcessPipeline(ImportTable importTable)
        {
            PipelineContext pipelineContext = new PipelineContext(importTable);

            return new DataProcessPipeline(pipelineContext);
        }


        /// <summary>
        /// 获取导入信息
        /// </summary>
        /// <typeparam name="T">导入的实体类型</typeparam>
        /// <param name="dataRow">首行数据(表头)</param>
        /// <returns></returns>
        private ImportTable CreateImportTable<T>() where T : class, new()
        {
            var type = typeof(T);

            if (_typeCaches.TryGetValue(type, out ImportTable importTable))
            {
                return importTable;
            }

            importTable = new ImportTable();

            importTable.Type = type;

            TableAttribute tableAttribute = type.GetCustomAttributes(typeof(TableAttribute), true).FirstOrDefault() as TableAttribute;
            if (tableAttribute == null) throw new ApplicationException($"类型{type.Name}未设定TableAttribute");
            if (string.IsNullOrEmpty(tableAttribute.Name)) throw new ApplicationException($"TableAttribute的Name属性不能为空");
            importTable.Name = tableAttribute.Name;

            var properties = type.GetProperties();
            if (properties.Length < 1) throw new ApplicationException($"类型{type.Name}未找到可用的属性");
            foreach (var property in properties)
            {
                ImportProperty importProperty = new ImportProperty();
                importProperty.PropertyName = property.Name;
                importProperty.DataType = property.PropertyType;

                importProperty.Attributes = property.GetCustomAttributes(true);

                OrdinalAttribute ordinalAttribute = property.GetCustomAttributes(typeof(OrdinalAttribute), true).FirstOrDefault() as OrdinalAttribute;
                if (ordinalAttribute != null)
                {
                    importProperty.Ordinal = ordinalAttribute.Index;
                }

                RequiredAttribute requiredAttribute = property.GetCustomAttributes(typeof(RequiredAttribute), true).FirstOrDefault() as RequiredAttribute;
                if (requiredAttribute != null)
                {
                    importProperty.IsRequired = true;
                }

                DataLengthAttribute dataLengthAttribute = property.GetCustomAttributes(typeof(DataLengthAttribute), true).FirstOrDefault() as DataLengthAttribute;
                if (dataLengthAttribute != null)
                {
                    importProperty.IsCheckLength = true;
                    importProperty.MinLength = dataLengthAttribute.MinLength;
                    importProperty.MaxLength = dataLengthAttribute.MaxLength;
                }

                ExcelUniqueAttribute checkUniqueAttribute = property.GetCustomAttributes(typeof(ExcelUniqueAttribute), true).FirstOrDefault() as ExcelUniqueAttribute;
                if (checkUniqueAttribute != null)
                {
                    importProperty.IsUnique = true;
                }

                object[] valueMappingAttributes = property.GetCustomAttributes(typeof(ValueMappingAttribute), true);

                if (valueMappingAttributes.Length > 0)
                {
                    if (!CheckValueMappingTypeIsSupport(importProperty.DataType))
                    {
                        throw new ApplicationException($"类型{type.Name}的{importProperty.PropertyName}属性类型不支持ValueMappingAttribute");
                    }
                }

                foreach (var valueMappingAttribute in valueMappingAttributes)
                {
                    var valueMapping = valueMappingAttribute as ValueMappingAttribute;
                    importProperty.ValueMappings.Add(valueMapping.Source, valueMapping.Destination);
                }

                importProperty.PropertyInfo = property;

                importTable.ImportProperties.Add(importProperty);
            }
            _typeCaches.TryAdd(type, importTable);

            return importTable;
        }

        /// <summary>
        /// 将Excel文件读取为DataTable
        /// </summary>
        /// <param name="stream">Excel的读取流</param>
        /// <returns></returns>
        private DataTable StreamToDataTable(Stream stream, ImportTable importTable)
        {
            using (var reader = ExcelReaderFactory.CreateReader(stream))
            {
                var ds = reader.AsDataSet(new ExcelDataSetConfiguration
                {
                    ConfigureDataTable = new Func<IExcelDataReader, ExcelDataTableConfiguration>(p =>
                    {
                        return new ExcelDataTableConfiguration
                        {
                            FilterColumn = new Func<IExcelDataReader, int, bool>((r, i) =>
                            {
                                // 去掉首行为空的列(没有表头的列)
                                return !r.IsDBNull(i);
                            })
                        };
                    })
                });
                if (ds.Tables.Count < 1) throw new ApplicationException("未找到一个可用的Sheet");

                var dt = ds.Tables[0];

                var headRow = dt.Rows[0];

                foreach (var importProperty in importTable.ImportProperties.Where(p => p.Ordinal.HasValue))
                {
                    importProperty.HeaderName = headRow[importProperty.Ordinal.Value]?.ToString();
                    dt.Columns[importProperty.Ordinal.Value].ColumnName = importProperty.PropertyName;
                }

                foreach (var importProperty in importTable.ImportProperties.Where(p => !p.Ordinal.HasValue))
                {
                    importProperty.HeaderName = importProperty.PropertyName;
                }

                return dt;
            }
        }

        public bool CheckValueMappingTypeIsSupport(Type type)
        {
            Type[] supportTypes = new Type[] {
                typeof(string),
                typeof(int),
                typeof(int?)
            };

            return supportTypes.Contains(type);
        }
        #endregion
    }
}
